#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/epoll.h>
#include <unordered_map>
#include "Sock.hpp"

#define SIZE 128
#define NUM 64

class Reactor;
class Event;

typedef int (*callback_t)(Event *ev); //定义函数指针类型

class Event
{
public:
    //对应的文件描述符
    int sock;
    //对应的sock,对应的输入缓冲区
    std::string inbuffer;
    //对应的sock,对应的输出缓冲区
    std::string outbuffer;
    // sock设置回调
    callback_t recver;
    callback_t sender;
    callback_t errorer;

    // 试着Event回指Reactor的指针
    Reactor *R;

public:
    Event()
    {
        sock = -1;
        recver = nullptr;
        sender = nullptr;
        errorer = nullptr;
        R = nullptr;
    }
    void RegisterCallback(callback_t _recver, callback_t _sender, callback_t _errorer)
    {
        recver = _recver;
        sender = _sender;
        errorer = _errorer;
    }
    ~Event()
    {
    }
};

// 不需要关心任何sock的类型(listen，读，写)
// 只关心如何使用该类，对Event进行管理
// Reactor : Event = 1 : n;
class Reactor //事件派发器
{
private:
    int epfd = -1;
    std::unordered_map<int, Event *> events; //我的Epoll类管理的所有的Event的集合
    //也可以不用map，epoll_event的data里有一个ptr指针可以用来指向Event
public:
    void InitReactor() //创建epfd
    {
        epfd = epoll_create(SIZE);
        if (epfd < 0)
        {
            exit(2);
        }
    }
    bool InsertEvent(Event *myev, uint32_t evs) // ev管理文件描述符的相关信息，evs代表要关心的事件
    {
        // 1. 将myev中的sock插入到epoll中
        struct epoll_event ev;
        ev.events = evs;
        ev.data.fd = myev->sock;
        if (epoll_ctl(epfd, EPOLL_CTL_ADD, myev->sock, &ev) < 0)
        {
            std::cerr << "epoll_ctl add event failed" << std::endl;
            return false;
        }
        // 2. 将ev本身插入到unordered_map中
        events.insert({myev->sock, myev});
    };
    //控制某一个sock，使能读写
    bool EnableRW(int sock, bool enRead, bool enWrite)
    {
        struct epoll_event ev;//修改的时候必须要以该结构体的形式传入
        ev.events = EPOLLET | (enRead ? EPOLLIN : 0) | (enWrite ? EPOLLOUT : 0);
        ev.data.fd = sock;
        if(epoll_ctl(epfd, EPOLL_CTL_MOD, sock, &ev) < 0)//修改该文件描述符对应的事件
        {
            std::cerr << "epoll_ctl mod event failed" << std::endl;
            return false;
        }
        return true;
    }
    //判断这个Sock文件描述符是否被删除了
    bool IsSockOk(int sock)
    {
        auto iter = events.find(sock);
        return iter != events.end();
    }
    void DeleteEvent(Event *evp)
    {
        int sock = evp->sock;
        auto it = events.find(sock);
        if (it != events.end())
        {
            // 1. 将sock中的sock从epoll中删除它
            epoll_ctl(epfd, EPOLL_CTL_DEL, sock, nullptr);

            // 2. 将特定的ev从 unordered_map中 移除
            events.erase(it);

            // 3. close
            close(sock);

            // 4. 删除event节点
            delete evp;
        }
    }
    //就绪事件的派发器逻辑
    void Dispatcher(int timeout)
    {
        struct epoll_event revs[NUM]; //就绪事件数组
        int n = epoll_wait(epfd, revs, NUM, timeout);
        for (int i = 0; i < n; i++)
        {
            int sock = revs[i].data.fd;
            uint32_t revents = revs[i].events;
            //代表差错处理, 将所有的错误问题全部转化成为让IO函数去解决
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);

            //读数据就绪,可能会有bug，后面解决
            if (revents & EPOLLIN)
            {
                //直接调用回调方法，执行对应的读取
                if (IsSockOk(sock) && events[sock]->recver)
                    events[sock]->recver(events[sock]);
            }
            if (revents & EPOLLOUT)
            {
                if (IsSockOk(sock) && events[sock]->sender)
                    events[sock]->sender(events[sock]);
            }
        }
    }
    ~Reactor()
    {
        close(epfd);
    }
};